#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
异常处理模块基本用法示例

该示例展示了异常处理模块的基本用法，包括自定义异常、异常处理装饰器、重试装饰器和异常上下文管理器。

创建时间: 2023-07-01
作者: Python Tools Team
"""

import time
from typing import Dict, Any

# 导入异常类型
from modules.exception.exception_types import (
    BaseAppException,
    DatabaseException,
    ValidationException,
    TimeoutException
)

# 导入异常处理工具
from modules.exception.exception_handler import (
    exception_handler,
    retry_on_exception,
    exception_context,
    ExceptionContext,
    log_exception,
    handle_exception
)

# 导入异常管理器
from modules.exception.exception_manager import (
    register_exception,
    register_global_handler,
    create_exception
)

# 导入日志管理器
from modules.logger import LogManager

# 创建日志记录器
logger = LogManager.get_both_logger(name="exception_example")


# 示例1: 自定义异常
@register_exception
class ConfigParseException(BaseAppException):
    """配置解析异常"""
    default_code = 5001


# 示例2: 使用异常处理装饰器
@exception_handler(exception_type=ValueError, reraise=False, default_return=0, logger=logger)
def divide(a: float, b: float) -> float:
    """除法运算，演示异常处理装饰器"""
    if b == 0:
        raise ValueError("除数不能为零")
    return a / b


# 示例3: 使用重试装饰器
@retry_on_exception(max_attempts=3, delay=0.5, exception_type=TimeoutException, logger=logger)
def fetch_data(resource_id: str) -> Dict[str, Any]:
    """模拟获取数据，演示重试装饰器"""
    logger.info(f"尝试获取资源: {resource_id}")
    
    # 模拟随机超时
    if time.time() % 3 < 1.5:  # 约50%的概率失败
        logger.warning(f"获取资源 {resource_id} 超时")
        raise TimeoutException(message=f"获取资源 {resource_id} 超时", code=4080)
    
    # 模拟成功获取数据
    return {"id": resource_id, "name": f"Resource {resource_id}", "status": "active"}


# 示例4: 使用异常上下文管理器
def process_data(data: Dict[str, Any]) -> Dict[str, Any]:
    """处理数据，演示异常上下文管理器"""
    result = {}
    
    # 使用类形式的上下文管理器
    with ExceptionContext(exception_type=KeyError, reraise=False, log_message="访问数据字段失败", logger=logger):
        result["name"] = data["name"].upper()
        result["status"] = data["status"]
        # 可能引发KeyError的操作
        result["category"] = data["category"]
    
    # 使用函数形式的上下文管理器
    with exception_context(exception_type=TypeError, reraise=True, reraise_as=ValidationException, logger=logger):
        # 可能引发TypeError的操作
        result["created_at"] = int(data.get("timestamp", "invalid"))
    
    return result


# 示例5: 全局异常处理器
@register_global_handler
def handle_database_errors(exc: Exception) -> bool:
    """处理数据库相关异常"""
    if isinstance(exc, DatabaseException):
        logger.error(f"数据库操作失败: {exc.message} (代码: {exc.code})")
        # 在这里可以添加数据库异常的特殊处理逻辑
        # 例如: 重新连接数据库、回滚事务等
        return True  # 表示已处理此异常
    return False  # 表示未处理此异常


# 示例6: 手动创建和抛出异常
def validate_user_input(user_input: Dict[str, Any]) -> None:
    """验证用户输入，演示手动创建和抛出异常"""
    if "username" not in user_input:
        # 创建并抛出验证异常
        raise create_exception(
            "ValidationException",
            "用户名不能为空",
            code=4001,
            details={"field": "username", "reason": "required"}
        )
    
    if len(user_input.get("password", "")) < 8:
        # 创建并抛出验证异常
        raise ValidationException(
            message="密码长度不足",
            code=4002,
            details={"field": "password", "reason": "too_short", "min_length": 8}
        )


# 示例7: 异常日志和处理工具函数
def process_file(file_path: str) -> None:
    """处理文件，演示异常日志和处理工具函数"""
    try:
        with open(file_path, 'r') as f:
            content = f.read()
            # 处理文件内容...
    except FileNotFoundError as e:
        # 记录异常日志
        log_exception(e, log_level="WARNING", message=f"文件不存在: {file_path}", logger=logger)
    except Exception as e:
        # 处理异常并重新抛出
        handle_exception(
            e,
            reraise=True,
            reraise_as=create_exception("FileException", f"处理文件 {file_path} 失败", cause=e),
            logger=logger
        )


def main():
    """主函数，运行所有示例"""
    logger.info("===== 异常处理模块基本用法示例 =====")
    
    # 示例1: 自定义异常
    logger.info("\n----- 示例1: 自定义异常 -----")
    try:
        raise ConfigParseException(message="配置文件格式错误", details={"line": 42, "column": 10})
    except BaseAppException as e:
        logger.error(f"捕获到应用异常: {e.message} (代码: {e.code})")
        logger.debug(f"异常详情: {e.to_dict()}")
    
    # 示例2: 使用异常处理装饰器
    logger.info("\n----- 示例2: 使用异常处理装饰器 -----")
    result1 = divide(10, 2)  # 正常情况
    logger.info(f"10 / 2 = {result1}")
    
    result2 = divide(10, 0)  # 异常情况，返回默认值0
    logger.info(f"10 / 0 = {result2}")
    
    # 示例3: 使用重试装饰器
    logger.info("\n----- 示例3: 使用重试装饰器 -----")
    try:
        data = fetch_data("12345")
        logger.info(f"获取到数据: {data}")
    except TimeoutException as e:
        logger.error(f"最终获取数据失败: {e.message}")
    
    # 示例4: 使用异常上下文管理器
    logger.info("\n----- 示例4: 使用异常上下文管理器 -----")
    sample_data = {"name": "test", "status": "pending", "timestamp": "1625097600"}
    try:
        processed = process_data(sample_data)
        logger.info(f"处理后的数据: {processed}")
    except ValidationException as e:
        logger.error(f"数据处理失败: {e.message}")
    
    # 示例5: 全局异常处理器 (这里只是注册，实际效果在未捕获异常时才会显示)
    logger.info("\n----- 示例5: 全局异常处理器 -----")
    logger.info("已注册全局数据库异常处理器")
    
    # 示例6: 手动创建和抛出异常
    logger.info("\n----- 示例6: 手动创建和抛出异常 -----")
    try:
        validate_user_input({"username": "user1", "password": "123"})
    except ValidationException as e:
        logger.error(f"输入验证失败: {e.message} (代码: {e.code})")
        logger.debug(f"验证详情: {e.details}")
    
    # 示例7: 异常日志和处理工具函数
    logger.info("\n----- 示例7: 异常日志和处理工具函数 -----")
    process_file("non_existent_file.txt")
    
    logger.info("\n===== 示例结束 =====")


if __name__ == "__main__":
    main()